/* Created on Jul 29, 2005
 *
 */
package org.mushroomdb.index;

import java.io.IOException;
import java.util.Collections;
import java.util.Iterator;

import org.apache.log4j.Logger;
import org.mushroomdb.catalog.Column;
import org.mushroomdb.catalog.Register;
import org.mushroomdb.catalog.Types;
import org.mushroomdb.catalog.encoding.EncoderFactory;
import org.mushroomdb.exception.RDBMSRuntimeException;
import org.mushroomdb.filemanagement.Page;
import org.mushroomdb.index.bplus.BPlusTree;
import org.mushroomdb.index.bplus.DataNode;
import org.mushroomdb.util.MultipleIterator;



/**
 * @author Matu
 *
 */
public class BPlusIndex implements Index {
	
	private String name;
	private Column column;
	private BPlusTree bPlusTree;
	private Logger logger;
	
	/**
	 * Constructor.
	 * @param name
	 * @param column
	 * @param page
	 */
	public BPlusIndex(String name, Column column, Page page) {
		this.logger = Logger.getLogger(this.getClass());
		this.name = name;
		this.column = column;
		int keySize = EncoderFactory.getInstance().getEncoderSize(Types.getJavaClass(column.getType())) * column.getSize();
		this.bPlusTree = new BPlusTree(
				page,
				Types.getJavaClass(column.getType()),
				keySize
				);
	}

	/**
	 * @see org.mushroomdb.index.Index#getName()
	 */
	public String getName() {
		return this.name;
	}
	
	/**
	 * @see org.mushroomdb.index.Index#getColumn()
	 */
	public Column getColumn() {
		return this.column;
	}

	/**
	 * @see org.mushroomdb.index.Index#insert(com.mdlm.rdbms.catalog.Register)
	 */
	public void insert(Register register, long pageNumber) {
		int index = register.getColumnIndex(this.column);
		if (index > 0) {
			Object key = register.getValue(index);
			try {
				this.bPlusTree.addKey(key,pageNumber);
			} catch (IOException e) {
				throw new RDBMSRuntimeException(e);
			}
			this.logger.warn("Index insertion: key " + key + " at page " + pageNumber); //$NON-NLS-1$ //$NON-NLS-2$
		} else {
			this.logger.warn("Column " + this.column + " does not belong to this index. Ignoring insertion."); //$NON-NLS-1$ //$NON-NLS-2$
		}
	}

	/**
	 * @see org.mushroomdb.index.Index#update(com.mdlm.rdbms.catalog.Register)
	 */
	public void update(Register register, int columnIndex, Object value) {
		// TODO: Si se updatea el campo indexado hay que borra y agregar.
		// this.removeKey(oldKey);
		//this.insert(register,value);
		this.logger.warn("No update was made to the index."); //$NON-NLS-1$ //$NON-NLS-2$
	}

	/**
	 * @see org.mushroomdb.index.Index#delete(com.mdlm.rdbms.catalog.Register)
	 */
	public void delete(Register register) {
		int index = register.getColumnIndex(this.column);
		Object key = register.getValue(index);
		try {
			this.bPlusTree.removeKey(key);
		} catch (IOException e) {
			throw new RDBMSRuntimeException(e);
		}
	}

	/**
	 * @see org.mushroomdb.index.Index#searchEqualsTo(java.lang.Object)
	 */
	public Iterator searchEqualsTo(Object key) {
		DataNode node = this.bPlusTree.getNode(key);
		if (node != null) {
			Page page = node.getPage(key);
			if (page != null) {
				TablePage tablePage = new TablePage(page,this.getColumn(),key);
				return tablePage.getRegisters();
			} else {
				this.logger.warn("The specified key could not be found in the data node.");
				return Collections.EMPTY_SET.iterator();
			}
		} else {
			this.logger.warn("The specified key could not be found in the index structure.");
			return Collections.EMPTY_SET.iterator();
		}
	}

	/**
	 * @see org.mushroomdb.index.Index#searchLessOrEqualThan(java.lang.Object)
	 */
	public Iterator searchLessOrEqualThan(Object key) {
		DataNode node = this.bPlusTree.getNode(key);
		TablePage tablePage = new TablePage(node.getPage(key),this.getColumn(),key);
		Iterator iterator = tablePage.getRegisters();
		
		node = node.getPreviousNode();
		while (node != null) {
			tablePage = new TablePage(node.getPage(key),this.getColumn(),key);
			iterator = new MultipleIterator(iterator,tablePage.getRegisters());
			node = node.getNextNode();
		}
		
		return iterator;
	}

	/**
	 * @see org.mushroomdb.index.Index#searchGreatherOrEqualThan(java.lang.Object)
	 */
	public Iterator searchGreatherOrEqualThan(Object key) {
		DataNode node = this.bPlusTree.getNode(key);
		TablePage tablePage = new TablePage(node.getPage(key),this.getColumn(),key);
		Iterator iterator = tablePage.getRegisters();
		
		node = node.getNextNode();
		while (node != null) {
			tablePage = new TablePage(node.getPage(key),this.getColumn(),key);
			iterator = new MultipleIterator(iterator,tablePage.getRegisters());
			node = node.getNextNode();
		}
		
		return iterator;
	}
}
